namespace BM.Tools.WebControls.MForm.Navigation.Predicates
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    using BM.Tools.WebControls.MForm.Navigation.XPath;

    /// <summary>
    /// <para>
    /// A navigator for the <see cref="PredicateFunction" /> locator.
    /// </para><para>
    /// The predicate can be either true or false. 
    /// Predicate navigator collects only those items, for which the predicate is true.
    /// </para>
    /// </summary>
    /// <typeparam name="T">
    /// The type of the navigable object.
    /// </typeparam>
    /// <typeparam name="TPredicate">
    /// the type of the predicate
    /// </typeparam>
    public abstract class PredicateNavigator<T, TPredicate> : Navigator<T, TPredicate>, IPredicateNavigator<T>
            where TPredicate : Predicate
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="PredicateNavigator{T, TPredicate}"/> class. 
        /// </summary>
        /// <param name="parent">
        /// The parent.
        /// </param>
        /// <param name="locator">
        /// The locator.
        /// </param>
        protected PredicateNavigator(INavigator<T> parent, TPredicate locator) : base(parent, locator)
        {
        }

        /// <summary>
        /// Gets the Predicate function.
        /// </summary>
        /// <value>
        /// The predicate function.
        /// </value>
        public virtual Func<T, bool> PredicateFunction
        {
            get
            {
                return Matches;
            }
        }

        /// <summary>
        /// An abstract method that needs to be overriden to define the predicate function.
        /// </summary>
        /// <param name="navigable">
        /// The navigable.
        /// </param>
        /// <returns>
        /// If the navigable item matches the constraint.
        /// </returns>
        public abstract bool Matches(T navigable);

        /// <summary>
        /// performs the selection by filtering the parent navigator selection with the predicate
        /// </summary>
        /// <returns>
        /// the enumerable of objects of type
        /// </returns>
        public override IEnumerable<T> Select()
        {
            return Parent.Select().Where(PredicateFunction);
        }
    }
}